package top.ddltech.stubborn.input;

/**
 * The GameAction class is an abstract to a user-initiated
 * action, like jumping or moving. GameActions can be mapped
 * to keys or the mouse with the InputManager.
 */
public class GameAction {

    /**
     * Normal behavior. The isPressed() method returns true
     * as long as the key is held down.
     */
    public static final int NORMAL = 0;

    /**
     * Initial press behavior. The isPressed() method returns
     * true only after the key is first pressed, and not again
     * until the key is released and pressed again.
     */
    public static final int DETECT_INITIAL_PRESS_ONLY = 1;

    private static final int STATE_RELEASED = 0;
    private static final int STATE_PRESSED = 1;
    private static final int STATE_WAITING_FOR_RELEASE = 2;

    private String name;
    private int behavior;
    private int amount;
    private int state;

    /**
     * Creates a new GameAction with the NORMAL behavior.
     */
    public GameAction(String name) {
        this(name, NORMAL);
    }

    /**
     * Creates a new GameAction with the specified behavior.
     */
    public GameAction(String name, int behavior) {
        this.name = name;
        this.behavior = behavior;
        reset();
    }

    /**
     * Gets the name of this GameAction.
     */
    public String getName() {
        return name;
    }

    /**
     * Resets this GameAction so that it appears like it hasn't
     * been pressed.
     */
    public void reset() {
        state = STATE_RELEASED;
        amount = 0;
    }

    /**
     * Tap this GameAction. Same as calling press() followed
     * by release().
     */
    public synchronized void tap() {
        press();
        release();
    }

    /**
     * Signals that the key was pressed.
     */
    public synchronized void press() {
        press(1);
    }

    /**
     * Signals that the key was pressed a specified number of
     * times, or that the mouse move a specified distance.
     */
    public synchronized void press(int amount) {
        if (state != STATE_WAITING_FOR_RELEASE) {
            this.amount += amount;
            state = STATE_PRESSED;
        }
    }

    /**
     * Signals that the key was released.
     */
    public synchronized void release() {
        state = STATE_RELEASED;
    }

    /**
     * Returns whether the key was pressed or not since last
     * checked.
     */
    public synchronized boolean isPressed() {
        return (getAmount() != 0);
    }

    /**
     * For keys, this is the number of times the key was
     * pressed since it was last checked.
     * For mouse movement, this is the distance moved.
     */
    public synchronized int getAmount() {
        int retVal = amount;
        if (retVal != 0) {
            if (state == STATE_RELEASED) {
                amount = 0;
            } else if (behavior == DETECT_INITIAL_PRESS_ONLY) {
                state = STATE_WAITING_FOR_RELEASE;
                amount = 0;
            }
        }
        return retVal;
    }
}
